﻿using System;
using System.ServiceProcess;
using System.Windows.Forms;
using System.Data.SqlClient;
using System.Data;
using System.ComponentModel;
using System.IO;
using System.Diagnostics;

namespace Autorun
{
	public partial class MainClientForm : Form, IPresenter
	{
		#region "Members"
		private ServerManagement _proxy;
		private ServiceController controller;
		private bool isBuiltIn;
		#endregion

		#region "Constructors and Destructors"
		public MainClientForm()
		{
			InitializeComponent();
		}
		#endregion

		#region "Form's Event Handlers"
		private void ClientForm_Load(object sender, EventArgs e)
		{
			Version ver;

			CheckForIllegalCrossThreadCalls = false;

			// === Set Program Information ============================================
			ver = new Version(Application.ProductVersion);
#if DEBUG
			Text = String.Format("[DEBUG] {0}", String.Format(Text, Application.ProductName, ApplicationStartInfo.StartMode.ToString(), ver.Major, ver.Minor, ver.Build, ver.Revision));
#else
			Text = String.Format(Text, Application.ProductName, ApplicationStartInfo.StartMode.ToString(), ver.Major, ver.Minor, ver.Build, ver.Revision);
#endif

			Proxy = null;
			LoadIcons();
			RefreshInformation();
			myObjectExplorer.Initialize(this, null);
			mnuHistory.Enabled = File.Exists("history.txt");
			mnuManual.Enabled = File.Exists("manual.pdf");

			ShowPane(typeof(ServerDashboard), null);
		}

		private void ClientForm_FormClosing(object sender, FormClosingEventArgs e)
		{
#if !DEBUG
			if (MessageBox.Show("Are you sure you want to quit?", Application.ProductName, MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.No)
				e.Cancel = true;
			else
			{
#endif
			ShowPane(null, null);

			try
			{
				if ((_proxy != null) && (_proxy.Service.Status == ServiceStatuses.Running) && (isBuiltIn == true))
					_proxy.Service.Stop();
			}
			catch { }
#if !DEBUG
			}
#endif
		}

		private void myRegisteredServers_ConnectServer(object sender, ConnectServerEventArgs e)
		{
			Connect(e.BuiltIn, e.Host, e.Port, e.Channel, false);
		}

		private void ClientForm_Resize(object sender, EventArgs e)
		{
			if (WindowState == FormWindowState.Minimized)
			{
				Hide();
				mySystray.Visible = true;
			}
		}
		#endregion

		#region "Private Procedures"
		public void Panic()
		{
			_proxy = null;
			mnuDisconnect_Click(null, null);
			MessageBox.Show("The connection with the remote server has been lost", Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
		}

		private void LoadIcons()
		{

			// === Load form icon ==================================================
			Icon = Properties.Resources.icoLogo;

			// === Load menu icons =================================================
			mnuConnect.Image = Properties.Resources.icoConnect2.ToBitmap();
			mnuDisconnect.Image = Properties.Resources.icoDisconnect.ToBitmap();
			mnuStart.Image = Properties.Resources.icoStart.ToBitmap();
			mnuStop.Image = Properties.Resources.icoStop.ToBitmap();

			// === Load Toolbar icons ==============================================
			btnConnect.Image = Properties.Resources.icoConnect2.ToBitmap();
			btnDisconnect.Image = Properties.Resources.icoDisconnect.ToBitmap();
			btnStart.Image = Properties.Resources.icoStart.ToBitmap();
			btnStop.Image = Properties.Resources.icoStop.ToBitmap();

			mySystray.Icon = Icon;
			mySystray.Text = Text;
		}

		private bool Connect(bool builtin, string host, int port, string channel, bool register)
		{
			Cursor = Cursors.WaitCursor;

			// === Close previous connection to server =======================
			if (Proxy != null)
				Proxy = null;

			// === Open the new connection ===================================
			if (builtin == true)
			{
				isBuiltIn = true;
				Proxy = ServerManagement.Instance;
			}
			else
			{
				isBuiltIn = false;
				// === Try to connect to the Service Controller ==============
				controller = new ServiceController("Autorun.ServerManagement", host);

				try
				{
					ServiceControllerStatus scs;
					scs = controller.Status;
				}
				catch (Exception ex)
				{
					// === Couldn't connect to the Service Controller ========
					controller = null;
#if DEBUG
					MessageBox.Show(ex.ToString());
#endif
				}

				try
				{
					Proxy = (ServerManagement)Activator.GetObject(
									 typeof(ServerManagement),
									 String.Format("{0}://{1}:{2}/{3}", channel, host, port, "ServerManagement"),
									 typeof(ServerManagement));
					string connectedDomain;
					connectedDomain = Proxy.Information.Domain;
					//TODO: Le AddHandler ne fonctionne pas pour des raisons de security policies
					//AddHandler My.Proxy.Engine.OnStatus, AddressOf myEngine_OnStatus
				}
				catch (Exception ex)
				{
#if DEBUG
					MessageBox.Show(ex.ToString());
#else
					MessageBox.Show("The server did not answer in a timely fashion.", Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Error);
#endif
					Proxy = null;
				}
			}

			// === Add the event handlers ====================================
			if (_proxy != null)
			{
				try
				{
					_proxy.Service.OnStart += new StartEventHandler(Service_OnStart);
					_proxy.Service.OnStop += new StopEventHandler(Service_OnStop);
					_proxy.Service.OnNotify += new NotifyEventHandler(Service_OnNotify);
				}
				catch 
				{
#if DEBUG
					MessageBox.Show("On remote servers, refresh is not automatic", Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Information);
#endif
				}
			}

			// === Refresh the Graphical User Interface ======================
			RefreshInformation();
			if (register == true)
				RegisterServer(host, port, channel);

			Cursor = Cursors.Default;

			// The initial ShowPane is controlled by ObjectExplorer
			//	ShowPane(typeof(PaneServer), new ShowPaneEventArgs(Proxy));


			return (Proxy != null);
		}

		private bool Disconnect()
		{
			try
			{
				_proxy.Service.OnStart -= Service_OnStart;
				_proxy.Service.OnStop -= Service_OnStop;
				_proxy.Service.OnNotify -= Service_OnNotify;
			}
			catch { }

			Proxy = null;
			RefreshInformation();
			ShowPane(typeof(ServerDashboard), null);
			return true;
		}

		private void RefreshInformation()
		{
			if (Proxy == null)
			{
				myNotification.Text = "Not connected";
				mnuConnect.Enabled = true;
				mnuDisconnect.Enabled = false;
				btnConnect.Enabled = true;
				btnDisconnect.Enabled = false;
				mnuStart.Enabled = false;
				mnuStop.Enabled = false;
				btnStart.Enabled = false;
				btnStop.Enabled = false;
			}
			else
			{
				myNotification.Text = string.Format("Connected to {0} (Domain: {1}, version: {2}) - {3}", Proxy.Information.MachineName, Proxy.Information.Domain, Proxy.Information.Version.ToString(), Proxy.Information.HomeDirectory);
				mnuConnect.Enabled = false;
				mnuDisconnect.Enabled = true;
				btnConnect.Enabled = false;
				btnDisconnect.Enabled = true;
				switch (_proxy.Service.Status)
				{
					case ServiceStatuses.Running:
						mnuStart.Enabled = false;
						mnuStop.Enabled = true;
						btnStart.Enabled = false;
						btnStop.Enabled = true;
						break;
					case ServiceStatuses.Stopped:
					default:
						mnuStart.Enabled = true;
						mnuStop.Enabled = false;
						btnStart.Enabled = true;
						btnStop.Enabled = false;
						break;
				}
			}
		}

		private void RegisterServer(string host, int port, string channel)
		{
			string query;
			int recId;

			query = string.Format("SELECT ISNULL((SELECT svrId FROM tblServer WHERE svrHost={0}),0)",
					SqlConvert.SqlString(host));

			recId = (int)ExecuteScalar(query);
			if (recId == 0)
			{
				query = string.Format("INSERT INTO tblServer(svrHost, svrPort, svrChannel) VALUES ({0},{1},{2})",
						SqlConvert.SqlString(host),
						port,
						SqlConvert.SqlString(channel));
				ExecuteNonQuery(query);
			}
			else
			{
				query = string.Format("UPDATE tblServer SET svrHost={0}, svrPort={1}, svrChannel={2} WHERE svrId={3}",
						SqlConvert.SqlString(host),
						port,
						SqlConvert.SqlString(channel),
						recId);
				ExecuteNonQuery(query);
			}
			myRegisteredServers.LoadRegisteredServers();
		}

		PaneBase GetPane(Type viewType)
		{
			PaneBase rc;

			rc = null;
			if (viewType != null)
			{
				try
				{
					rc = (PaneBase)Activator.CreateInstance(viewType);
				}
				catch (MissingMethodException ex)
				{
					MessageBox.Show(String.Format("Cannot find a valid constructor that might accept parameters for the view [{0}].", viewType), Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Error);
				}
				catch (TypeLoadException ex)
				{
					MessageBox.Show(String.Format("The requested view [{0}] has not been found", viewType), Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Error);
				}
				catch (InvalidCastException ex)
				{
					MessageBox.Show(String.Format("The requested view [{0}] doesn't implement the IViewBase interface", viewType), Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Error);
				}
				catch (Exception ex)
				{
					MessageBox.Show(String.Format("An unhandled error occured while loading the view [{0}]:\n{1}", viewType, ex.ToString()), Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Error);
				}
			}

			return rc;
		}
		#endregion

		#region "Properties"
		ServerManagement Proxy
		{
			get { return _proxy; }
			set
			{
				_proxy = value;
				myObjectExplorer.Proxy = _proxy;
			}
		}
		#endregion

		#region IPresenter Members
		public event ChangePaneEventHandler OnChangingPane;

		public bool ShowPane(Type viewType, ShowPaneEventArgs e)
		{
			ChangePaneEventArgs cancel;
			PaneBase newPane;
			PaneBase oldPane;

			Cursor = Cursors.WaitCursor;

			cancel = new ChangePaneEventArgs();
			newPane = null;

			// === Ask the current pane to change ==================================
			if (myContainer.Panel2.Controls.Count == 0)
				oldPane = null;
			else
			{
				oldPane = (PaneBase)myContainer.Panel2.Controls[0];
				if (OnChangingPane != null)
					OnChangingPane(this, cancel);
			}

			if (cancel.Cancel == false)
			{
				if (viewType != null)
				{
					newPane = GetPane(viewType);
					if (newPane != null)
					{
						cancel.Cancel = !newPane.Initialize(this, e);
#if DEBUG
						if (cancel.Cancel == true)
							MessageBox.Show(string.Format("Initialization of the pane '{0}' failed.", viewType.ToString()), Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Error);
#endif
					}
					else
						cancel.Cancel = true;
				}

				if (cancel.Cancel == false)
				{
					if (myContainer.Panel2.Controls.Count != 0)
						myContainer.Panel2.Controls[0].Dispose();
					myContainer.Panel2.Controls.Clear();

					if (newPane != null)
					{
						newPane.Dock = DockStyle.Fill;
						newPane.BringToFront();
						newPane.Visible = true;
					}

					myContainer.Panel2.Controls.Add(newPane);

				}

				if (oldPane != null)
					oldPane.Terminate();
			}

			Cursor = Cursors.Default;
			return true;
		}

		#endregion

		#region "Menu Management"
		private void mnuConnect_Click(object sender, EventArgs e)
		{
			ConnectDialog dlg;
			DialogResult rc;

			dlg = new ConnectDialog();
			rc = dlg.ShowDialog();
			if (rc == DialogResult.OK)
				Connect(dlg.BuiltIn, dlg.Host, dlg.Port, dlg.Channel, dlg.Register);
		}

		private void mnuDisconnect_Click(object sender, EventArgs e)
		{
			Disconnect();
		}

		private void mnuStart_Click(object sender, EventArgs e)
		{
			Cursor = Cursors.WaitCursor;
			_proxy.Service.Start();
			RefreshInformation();
			Cursor = Cursors.Default;
		}

		private void mnuStop_Click(object sender, EventArgs e)
		{
			Cursor = Cursors.WaitCursor;
			_proxy.Service.Stop();
			RefreshInformation();
			Cursor = Cursors.Default;
		}

		private void mnuAbout_Click(object sender, EventArgs e)
		{
			AboutDialog dlg;

			dlg = new AboutDialog();
			dlg.ShowDialog(this);
		}

		private void mnuQuit_Click(object sender, EventArgs e)
		{
			Close();
		}

		private void mnuHistory_Click(object sender, EventArgs e)
		{
			Process.Start("history.txt");
		}
		private void btnRestore_Click(object sender, EventArgs e)
		{
			Show();

			WindowState = FormWindowState.Normal;
			mySystray.Visible = false;
			ShowInTaskbar = true;
		}
		#endregion

		#region "ServerManagement Events handlers"

		void Service_OnNotify(object sender, NotifyEventArgs e)
		{
			myNotification.Text = string.Format("{0}: {1}", DateTime.Now, e.Message);
		}

		void Service_OnStop(object sender, StopEventArgs e)
		{
			myNotification.Text = string.Format("{0}: Service stopped", DateTime.Now);
		}

		void Service_OnStart(object sender, StartEventArgs e)
		{
			myNotification.Text = string.Format("{0}: Service started", DateTime.Now);
		}
		#endregion

		#region "Data Access Methods"
		private void ExecuteNonQuery(string query)
		{
			SqlConnection cn;
			SqlCommand cmd;

			cn = new SqlConnection(Properties.Settings.Default.ConnectionString);

			try
			{
				cn.Open();
				cmd = cn.CreateCommand();
				cmd.CommandText = query;
				cmd.ExecuteNonQuery();
				cmd.Connection = null;
				cmd = null;
			}
			finally
			{
				cn.Close();
			}
		}

		private object ExecuteScalar(string query)
		{
			SqlConnection cn;
			SqlCommand cmd;
			object rc = null;

			cn = new SqlConnection(Properties.Settings.Default.ConnectionString);

			try
			{
				cn.Open();
				cmd = cn.CreateCommand();
				cmd.CommandText = query;
				rc = cmd.ExecuteScalar();
				cmd.Connection = null;
				cmd = null;
			}
			finally
			{
				cn.Close();
			}

			return rc;
		}

		private DataTable ExecuteDataTable(string query)
		{
			SqlDataAdapter da;
			DataSet rc;

			da = new SqlDataAdapter(query, Properties.Settings.Default.ConnectionString);
			rc = new DataSet();
			da.Fill(rc);
			return rc.Tables.Count != 0 ? rc.Tables[0] : null;
		}
		#endregion

		#region "Controls Events Handlers"
		private void mySystray_MouseDoubleClick(object sender, MouseEventArgs e)
		{
			btnRestore_Click(null, null);
		}
		#endregion

		private void mnuManual_Click(object sender, EventArgs e)
		{
			Process.Start("manual.pdf");
		}
	}
}
